package org.de.maeyer.unit;

import java.util.concurrent.TimeUnit;

/**
 * @author Peter De Maeyer
 */
public class UnitUtils {

	/** SI unit of time. */
	public static final Unit SECOND = new NamedUnit("second", "s");

	/** Unit of time. */
	public static final Unit MINUTE = new NamedMultiplyingUnit("minute", "min", 60., SECOND);

	/** Unit of time. */
	public static final Unit HOUR = new NamedMultiplyingUnit("hour", "h", 3600., SECOND);

	/** Unit of time. */
	public static final Unit DAY = new NamedMultiplyingUnit("day", "d", 86400., SECOND);
	
	/** Unit of time. */
	public static final Unit NANOSECOND = nano(SECOND);
	
	/** Unit of time. */
	public static final Unit MICROSECOND = micro(SECOND);
	
	/** Unit of time. */
	public static final Unit MILLISECOND = milli(SECOND);

	/** SI unit of length. */
	public static final Unit METER = new NamedUnit("meter", "m");

	/** Unit of size. */
	public static final Unit BYTE = new NamedUnit("byte", "B");

	/** Unit of size. */
	public static final Unit BIT = new NamedMultiplyingUnit("bit", "b", .125, BYTE);

	/** Unit of mass. */
	public static final Unit GRAM = new NamedUnit("gram", "g");

	/** SI unit of mass. */
	public static final Unit KILOGRAM = kilo(GRAM);

	/** SI unit of electric current. */
	public static final Unit AMPERE = new NamedUnit("ampère", "A");

	/** Unit of electric resistance. */
	public static final Unit OHM = new NamedUnit("ohm", "\u03a9");

	/** Unit of electrical potential difference. */
	public static final Unit VOLT = new NamedUnit("volt", "V");

	/** SI unit of thermodynamic temperature. */
	public static final Unit KELVIN = new NamedUnit("kelvin", "K");

	/** SI unit of amount of substance. */
	public static final Unit MOLE = new NamedUnit("mole", "mol");

	/** SI unit of luminous intensity. */
	public static final Unit CANDELA = new NamedUnit("candela", "cd");

	/** Unit of energy. */
	public static final Unit JOULE = new NamedUnit("joule", "J");

	/** Unit of force. */
	public static final Unit NEWTON = new NamedUnit("newton", "N");

	/** Unit of power. */
	public static final Unit WATT = new NamedUnit("watt", "W");

	private UnitUtils() {
	}

	/** 10^-24. */
	public static Unit yocto(Unit prefixedUnit) {
		return new PrefixingUnit("yocto", "y", 1.e-24, prefixedUnit);
	}

	/** 10^-21. */
	public static Unit zepto(Unit prefixedUnit) {
		return new PrefixingUnit("zepto", "z", 1.e-21, prefixedUnit);
	}

	/** 10^-18. */
	public static Unit atto(Unit prefixedUnit) {
		return new PrefixingUnit("atto", "a", 1.e-18, prefixedUnit);
	}

	/** 10^-15. */
	public static Unit femto(Unit prefixedUnit) {
		return new PrefixingUnit("femto", "f", 1.e-15, prefixedUnit);
	}

	public static Unit pico(Unit prefixedUnit) {
		return new PrefixingUnit("pico", "p", 1.e-12, prefixedUnit);
	}

	public static Unit nano(Unit prefixedUnit) {
		return new PrefixingUnit("nano", "n", 1.e-9, prefixedUnit);
	}

	public static Unit micro(Unit prefixedUnit) {
		return new PrefixingUnit("micro", "µ", 1.e-6, prefixedUnit);
	}

	public static Unit milli(Unit prefixedUnit) {
		return new PrefixingUnit("milli", "m", 1.e-3, prefixedUnit);
	}

	public static Unit centi(Unit prefixedUnit) {
		return new PrefixingUnit("centi", "c", 1.e-2, prefixedUnit);
	}

	public static Unit deci(Unit prefixedUnit) {
		return new PrefixingUnit("deci", "d", 1.e-1, prefixedUnit);
	}

	public static Unit deca(Unit prefixedUnit) {
		return new PrefixingUnit("deca", "da", 1.e1, prefixedUnit);
	}

	public static Unit hecto(Unit prefixedUnit) {
		return new PrefixingUnit("hecto", "h", 1.e2, prefixedUnit);
	}

	public static Unit kilo(Unit prefixedUnit) {
		return new PrefixingUnit("kilo", "k", 1.e3, prefixedUnit);
	}

	public static Unit kibi(Unit prefixedUnit) {
		return new PrefixingUnit("kibi", "ki", (double) 1024L, prefixedUnit);
	}

	public static Unit mega(Unit prefixedUnit) {
		return new PrefixingUnit("mega", "M", 1.e6, prefixedUnit);
	}

	public static Unit mebi(Unit prefixedUnit) {
		return new PrefixingUnit("mebi", "Mi", (double) 1048576L, prefixedUnit);
	}

	public static Unit giga(Unit prefixedUnit) {
		return new PrefixingUnit("giga", "G", 1.e9, prefixedUnit);
	}

	public static Unit gibi(Unit prefixedUnit) {
		return new PrefixingUnit("gibi", "Gi", (double) 1073741824L, prefixedUnit);
	}

	public static Unit tera(Unit prefixedUnit) {
		return new PrefixingUnit("tera", "T", 1.e12, prefixedUnit);
	}

	public static Unit tebi(Unit prefixedUnit) {
		return new PrefixingUnit("tebi", "Ti", (double) 1099511627776L, prefixedUnit);
	}

	/** 10^15. */
	public static Unit peta(Unit prefixedUnit) {
		return new PrefixingUnit("peta", "P", 1.e15, prefixedUnit);
	}

	/** 1024^5. */
	public static Unit pebi(Unit prefixedUnit) {
		return new PrefixingUnit("pebi", "Pi", (double) 1125899906842624L, prefixedUnit);
	}

	/** 10^18. */
	public static Unit exa(Unit prefixedUnit) {
		return new PrefixingUnit("exa", "E", 1.e18, prefixedUnit);
	}

	/** 1024^6. */
	public static Unit exbi(Unit prefixedUnit) {
		return new PrefixingUnit("exbi", "Ei", (double) 1152921504606846976L, prefixedUnit);
	}

	/** 10^21. */
	public static Unit zetta(Unit prefixedUnit) {
		return new PrefixingUnit("zetta", "Z", 1.e21, prefixedUnit);
	}

	/** 10^24. */
	public static Unit yotta(Unit prefixedUnit) {
		return new PrefixingUnit("yotta", "Y", 1.e24, prefixedUnit);
	}

	public static Unit square(Unit suffixedUnit) {
		return new SuffixingUnit("square ", "²", suffixedUnit);
	}

	public static Unit cubic(Unit suffixedUnit) {
		return new SuffixingUnit("cubic ", "³", suffixedUnit);
	}
	
	public static Unit unitFromTimeUnit(TimeUnit timeUnit) {
		switch (timeUnit) {
		case NANOSECONDS: return NANOSECOND;
		case MICROSECONDS: return MICROSECOND;
		case MILLISECONDS: return MILLISECOND;
		case SECONDS: return SECOND;
		case MINUTES: return MINUTE;
		case HOURS: return HOUR;
		case DAYS: return DAY;
		}
		throw new IllegalArgumentException(String.valueOf(timeUnit));
	}
}
